﻿// // Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
// //
// // Licensed under the Apache License, Version 2.0 (the "License");
// // you may not use this file except in compliance with the License.
// // You may obtain a copy of the License at
// //
// //     http://www.apache.org/licenses/LICENSE-2.0
// //
// // Unless required by applicable law or agreed to in writing, software
// // distributed under the License is distributed on an "AS IS" BASIS,
// // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// // See the License for the specific language governing permissions and
// // limitations under the License.



#include "processor.h"

namespace ai {

// void PreProcessor::normalize(cv::Mat& im, float* data, PDModelConfig *cfg)
// {
//     int rh = im.rows;
//     int rw = im.cols;
//     int rc = im.channels();
//     double normf = static_cast<double>(1.0) / 255.0;
//     #pragma omp parallel for
//     for (int h = 0; h < rh; ++h) {
//         const uchar* ptr = im.ptr<uchar>(h);
//         int im_index = 0;
//         for (int w = 0; w < rw; ++w) {
//             for (int c = 0; c < rc; ++c) {
//                 int top_index = (c * rh + h) * rw + w;
//                 float pixel = static_cast<float>(ptr[im_index++]);
//                 pixel = (pixel * normf - cfg->mean[c]) / cfg->std[c];
//                 data[top_index] = pixel;
//             }
//         }
//     }
// }


// void PreProcessor::det_normalize(cv::Mat* im, ImageBlob* data, PDModelConfig* cfg)
// {
//     double e = 1.0;
//     // if(cfg->is_scale){
//         e /= 255.0;
//     // }
//     (*im).convertTo(*im, CV_32FC3, e);
//     for (int h = 0; h < im->rows; h++) {
//         for (int w = 0; w < im->cols; w++) {
//             im->at<cv::Vec3f>(h, w)[0] =
//                 (im->at<cv::Vec3f>(h, w)[0] - cfg->mean[0] ) / cfg->std[0];
//             im->at<cv::Vec3f>(h, w)[1] =
//                 (im->at<cv::Vec3f>(h, w)[1] - cfg->mean[1] ) / cfg->std[1];
//             im->at<cv::Vec3f>(h, w)[2] =
//                 (im->at<cv::Vec3f>(h, w)[2] - cfg->mean[2] ) / cfg->std[2];
//         }
//     }
// }


// void PreProcessor::flatten_mat(cv::Mat& im, float* data, PDModelConfig *cfg)
// {
//     int rh = im.rows;
//     int rw = im.cols;
//     int rc = im.channels();
//     #pragma omp parallel for
//     for (int h = 0; h < rh; ++h) {
//         const uchar* ptr = im.ptr<uchar>(h);
//         int im_index = 0;
//         int top_index = h * rw * rc;
//         for (int w = 0; w < rw; ++w) {
//             for (int c = 0; c < rc; ++c) {
//                 float pixel = static_cast<float>(ptr[im_index++]);
//                 data[top_index++] = pixel;
//             }
//         }
//     }
// }

// void PreProcessor::det_resize_scale(cv::Mat* im, ImageBlob* data, PDModelConfig *cfg)
// {
//     std::pair<float, float> scale;
//     int origin_w = im->cols;
//     int origin_h = im->rows;

//     // 等比缩放
//     if (cfg->algorithm == pd_cls) {
//         scale.second = static_cast<float>(cfg->image_shape[1]) / \
//                         static_cast<float>(origin_w);
//         scale.first = static_cast<float>(cfg->image_shape[0]) / \
//                         static_cast<float>(origin_h);
//         // float wr = cfg->image_shape[1] * 1.0 / origin_w;
//         // float hr = cfg->image_shape[0] * 1.0 / origin_h;
//         // scale.first = std::min(wr, hr);
//         // scale.second = std::min(wr, hr);
//     } 
//     // 等比缩放
//     else if(cfg->algorithm == pd_det && (cfg->arch == "RetinaNet" || 
//         cfg->arch == "RCNN")) {
//         float wr = cfg->image_shape[1] * 1.0 / origin_w;
//         float hr = cfg->image_shape[0] * 1.0 / origin_h;
//         scale.first = std::min(wr, hr);
//         scale.second = std::min(wr, hr);
//     } 
//     // 缩放填充
//     else 
//     {
//         scale.second = static_cast<float>(cfg->image_shape[1]) / \
//                         static_cast<float>(origin_w);
//         scale.first = static_cast<float>(cfg->image_shape[0]) / \
//                         static_cast<float>(origin_h);
//     }
//     data->scale_factor = {
//         scale.first, 
//         scale.second

//     }; // y, x
// }


// void PreProcessor::det_resize(cv::Mat* im, ImageBlob* data, PDModelConfig *cfg)
// {
//     det_resize_scale(im, data, cfg);
//     cv::resize(*im, *im, cv::Size(), data->scale_factor[1], 
//                 data->scale_factor[0], cv::INTER_CUBIC);
//     // Padding the image with 0 border
//     cv::copyMakeBorder(
//         *im,
//         *im,
//         0,
//         cfg->image_shape[0] - im->rows,
//         0,
//         cfg->image_shape[1] - im->cols,
//         cv::BORDER_CONSTANT,
//         cv::Scalar(0, 0, 0));

//     data->input_shape = {
//         static_cast<float>(im->rows),
//         static_cast<float>(im->cols),
//     };
//     // cover // 更新输入尺寸
//     data->ori_im_shape = {im->rows, im->cols};
// }


// void PreProcessor::cla_resize(const cv::Mat &img, cv::Mat &resize_img,
//                     int resize_short_size) {
//   int w = img.cols;
//   int h = img.rows;

//   float ratio = 1.f;
//   if (h < w) {
//     ratio = float(resize_short_size) / float(h);
//   } else {
//     ratio = float(resize_short_size) / float(w);
//   }

//   int resize_h = round(float(h) * ratio);
//   int resize_w = round(float(w) * ratio);

//   cv::resize(img, resize_img, cv::Size(resize_w, resize_h));
// }

// void PreProcessor::det_pad_stride(cv::Mat* im, ImageBlob* data, PDModelConfig *cfg)
// {
//     // if (cfg->pad_stride <= 0) {
//     //     return;
//     // }
//     // int rc = im->channels();
//     // int rh = im->rows;
//     // int rw = im->cols;
//     // int nh = rh / cfg->pad_stride * cfg->pad_stride + \
//     //             (rh / cfg->pad_stride!=0) * cfg->pad_stride;
//     // int nw = rw / cfg->pad_stride * cfg->pad_stride + \
//     //             (rw / cfg->pad_stride!=0) * cfg->pad_stride;
//     // cv::copyMakeBorder(
//     //     *im,
//     //     *im,
//     //     0,
//     //     nh - rh,
//     //     0,
//     //     nw - rw,
//     //     cv::BORDER_CONSTANT,
//     //     cv::Scalar(0));
//     // (data->eval_im_shape)[0] = static_cast<float>(im->rows);
//     // (data->eval_im_shape)[1] = static_cast<float>(im->cols);
// }

// void PreProcessor::det_permute(cv::Mat* im, ImageBlob* data, PDModelConfig *cfg)
// {
//     int rh = im->rows;
//     int rw = im->cols;
//     int rc = im->channels();
//     for (int i = 0; i < rc; ++i) {
//         int cur_c = cfg->img_type == "rgb" ? rc - i - 1 : i;
//         cv::extractChannel(*im, cv::Mat(rh, rw, CV_32FC1, 
//                             data->im_data + cur_c * rh * rw), i);
//     }
// }

// void PreProcessor::cla_permute(const cv::Mat *im, float *data) {
//   int rh = im->rows;
//   int rw = im->cols;
//   int rc = im->channels();
//   for (int i = 0; i < rc; ++i) {
//     cv::extractChannel(*im, cv::Mat(rh, rw, CV_32FC1, data + i * rh * rw), i);
//   }
// }


void PostProcessor::argmax(float* out, std::vector<int>& shape,
                    std::vector<uchar>& mask, std::vector<uchar>& scoremap) {
    int out_img_len = shape[1] * shape[2];
    int blob_out_len = out_img_len * shape[0];
    /*
    Eigen::TensorMap<Eigen::Tensor<float, 3>> out_3d(out, shape[0], shape[1], shape[2]);
    Eigen::Tensor<Eigen::DenseIndex, 2> argmax = out_3d.argmax(0);
    */
    float max_value = -1;
    int label = 0;
    #pragma omp parallel private(label)
    for (int i = 0; i < out_img_len; ++i) {
        max_value = -1;
        label = 0;
        #pragma omp for reduction(max : max_value)
        for (int j = 0; j < shape[0]; ++j) {
            int index = i + j * out_img_len;
            if (index >= blob_out_len) {
                continue;
            }
            float value = out[index];
            if (value > max_value) {
                max_value = value;
                label = j;
            }
        }
        if (label == 0) max_value = 0;
        mask[i] = uchar(label);
        scoremap[i] = uchar(max_value * 255);
    }
}


}  // namespace paddle_infer
